package com.jrtc.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jrtc.base.config.constants.Constants;
import com.jrtc.base.config.constants.PublicConstants;
import com.jrtc.base.entity.bo.*;
import com.jrtc.base.entity.vo.*;
import com.jrtc.base.util.*;
import com.jrtc.dao.*;
import com.jrtc.service.DoctorService;
import com.jrtc.service.PatientService;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 患者表(Patient)表服务实现类
 *
 * @author makejava
 * @since 2022-03-21 17:34:12
 */
@Service("patientService")
public class PatientServiceImpl implements PatientService
{
    @Resource
    private PatientDao patientDao;
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private HealthplanDao healthplanDao;
    @Resource
    private PatientExerciseprescriptionDao patientExerciseprescriptionDao;
    @Resource
    private ExerciseprescriptionDao exerciseprescriptionDao;
    @Resource
    private PatientAppointmentDao patientAppointmentDao;
    @Resource
    private DoctorDao doctorDao;
    @Resource
    private DoctorService doctorService;
    @Resource
    private RoleDao roleDao;
    @Resource
    private MinioUtil minioUtil;

    /**
     * 通过ID查询单条数据
     *
     * @param patientId 主键
     * @return 实例对象
     */
    @Override
    public Patient queryById(Integer patientId) {
        return this.patientDao.queryById(patientId);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    @Override
    public List<Patient> queryAllByLimit(int offset, int limit) {
        return this.patientDao.queryAllByLimit(offset, limit);
    }

    @Override
    public IPage<Patient> queryPatientList(Patient patient) {
        Page<Patient> page = new Page<>(patient.getPageNo(), patient.getPageSize());
        IPage<Patient> patientPage = this.patientDao.queryPatientList(page, patient);
        return patientPage;
    }
    /**
     * 新增数据
     *
     * @param patient 实例对象
     * @return 实例对象
     */
    @Override
    public Patient insert(Patient patient) {
        this.patientDao.insert(patient);
        return patient;
    }

    /**
     * 修改数据
     *
     * @param patient 实例对象
     * @return 实例对象
     */
    @Override
    public Patient update(Patient patient) {
        this.patientDao.update(patient);
        return this.queryById(patient.getPatientId());
    }

    /**
     * 通过主键删除数据
     *
     * @param patientId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer patientId) {
        return this.patientDao.deleteById(patientId) > 0;
    }

    /**
     * 查询患者列表
     * */
    @Override
    public List<PatientVo> patientList(String patientName, int pageNum, int pageSize) throws Exception {
        if (patientName != null){
            patientName = "%" + patientName + "%";
        }
        int pageNo = pageSize;
        pageSize = (pageNum - 1) * pageSize;
        if (pageSize==0)
        {
            pageSize = pageNo;
        }
        pageNum = pageNum -1;
        List<Patient> patients = patientDao.patientList(patientName, pageNum, pageSize);
        if (patients != null && patients.size() > 0){
            List<PatientVo> patientVoList = patientVo(patients);
            return patientVoList;
        }
        else {
            throw new Exception("未查到患者信息");
        }
    }

    /**
     * 创建新病人
     * */
    @Override
    public int createNewPatient(Patient patient, HttpServletRequest request) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String count = "123456";
        String password = KeyUtils.desEncrypt(count, null).toLowerCase();
        patient.setPassword(password);

        Doctor loginDoctor;
        try {
            loginDoctor = doctorService.getLoginDoctor(request);
        } catch (Exception e){
            throw new Exception(e.getMessage());
        }

        if (loginDoctor != null){
            patient.setDoctorId(loginDoctor.getDoctorId());
            patient.setHospitalCode(loginDoctor.getHospitalCode());
        }

        if (patient != null){
            if (patient.getAvatar() == null || patient.getAvatar().equals("")){
                patient.setAvatar("download/prescription/document/2022/08/15/c0fb0a1f-f2fe-4959-88f6-9f78ac3ce493.jpg");
            }

            if (patient.getBirthday() != null && !patient.getBirthday().equals("")){
                int ageByBirthday = AgeUtil.getAgeByBirthday(patient.getBirthday().toString());
                patient.setAge(ageByBirthday);
            }
            else {
                throw new Exception("生日不能为空");
            }
            Date date = new Date();
            String registerTime = format.format(date);
            patient.setRegisterTime(registerTime);

            int newPatient = patientDao.createNewPatient(patient);
            if (newPatient > 0){
                return newPatient;
            }
            else {
                throw new Exception("添加失败");
            }
        }
        else {
            throw new Exception("缺少必要参数");
        }
    }

    /**
     * 患者账号密码登录
     * */
    @Override
    public Patient login(PatientLoginVo patientLoginVo) {
        Patient patient = new Patient();
        patient.setPhone(patientLoginVo.getPhone());
        try {
            patient.setPassword(KeyUtils.desEncrypt(patientLoginVo.getPassword(), null).toLowerCase());
        } catch (Exception e){
            System.out.println(e);
        }

        Patient patientDB = this.patientDao.login(patient);
        if (patientDB == null)
        {
            return null;
        }
        Collection<String> keys = redisUtil.keys(Constants.DOCTOR_LOGIN_TOKEN_KEY.getValue() + patientLoginVo.getPhone() + "*");
        if (keys != null && keys.size() > 0)
        {
            for (String key : keys)
                redisUtil.del(key);
        }
        String token = IdUtils.fastUUID();
        patientDB.setToken(token);
        redisUtil.set(Constants.DOCTOR_LOGIN_TOKEN_KEY.getValue() + token, JSON.toJSON(patientDB), 3 * 24 * 60 * 60);
        return patientDB;
    }

    /**
     * 根据token获取患者信息
     * */
    @Override
    public Patient getLoginPatient(HttpServletRequest request) throws Exception {
        String token = request.getHeader("token");
        if (token != null && !token.equals("")){
            Object object = redisUtil.get(Constants.DOCTOR_LOGIN_TOKEN_KEY.getValue() + token);
            if (object != null){
                JSONObject json = JSONObject.fromObject(object);
                Patient patient = (Patient)JSONObject.toBean(json, Patient.class);
                return patient;
            }
            else {
                throw new Exception("登录已过期");
            }
        }
        else {
            throw new Exception("没有获取到token");
        }
    }

    /**
     * 补充患者信息
     * */
    @Transactional
    @Override
    public int selectPatient(PatientParameterVo patientParameterVo) throws Exception {
        if (patientParameterVo.getPatientId() != null && patientParameterVo.getPatientId() != 0 &&
                patientParameterVo.getHeight() != null && patientParameterVo.getHeight() != 0 &&
                patientParameterVo.getWeight() != null && patientParameterVo.getWeight() != 0 &&
                patientParameterVo.getRestingHeartRate() != null && patientParameterVo.getRestingHeartRate() != 0 &&
                patientParameterVo.getSportsTargetList() != null && patientParameterVo.getSportsTargetList().size() > 0 &&
                patientParameterVo.getStandardOfLiving() != null && !patientParameterVo.getStandardOfLiving().equals("")){

            Patient patient = patientDao.selectPatient(patientParameterVo.getPatientId());
            if (patient != null){
                if (patientParameterVo.getPatientName() != null && !patientParameterVo.getPatientName().equals("")){
                    patient.setPatientName(patientParameterVo.getPatientName());
                }
                else {
                    patient.setPatientName(patient.getPatientName());
                }

                if (patientParameterVo.getBirthday() != null && !patientParameterVo.getBirthday().equals("")){
                    patient.setBirthday(patientParameterVo.getBirthday());
                    int ageByBirthday = AgeUtil.getAgeByBirthday(patientParameterVo.getBirthday().toString());
                    patient.setAge(ageByBirthday);
                }
                else {
                    patient.setBirthday(patient.getBirthday());
                    patient.setAge(patient.getAge());
                }

                if (patientParameterVo.getSex() != null && !patientParameterVo.getSex().equals("")){
                    patient.setSex(patientParameterVo.getSex());
                }
                else {
                    patient.setSex(patient.getSex());
                }

                patient.setHeight(patientParameterVo.getHeight());
                if (patientParameterVo.getType().equals(PublicConstants.weightUnit.Kilogram.getValue())){
                    patient.setWeight(patientParameterVo.getWeight() * 2);
                }
                else {
                    patient.setWeight(patientParameterVo.getWeight());
                }

                patient.setRestingHeartRate(patientParameterVo.getRestingHeartRate());

                int i = patientDao.updatePatient(patient);
                if (i > 0){
                    Healthplan healthplan = new Healthplan();
                    healthplan.setPatientId(patientParameterVo.getPatientId());
                    String sportsTarget = "";
                    for (int j = 0 ; j < patientParameterVo.getSportsTargetList().size() ; j++) {
                        if (j == 0){
                            sportsTarget = patientParameterVo.getSportsTargetList().get(j);
                        }
                        sportsTarget = sportsTarget + "," + patientParameterVo.getSportsTargetList().get(j);
                    }
                    healthplan.setSportsTarget(sportsTarget);
                    healthplan.setStandardOfLiving(patientParameterVo.getStandardOfLiving());
                    int insertHealthplan = healthplanDao.insertHealthplan(healthplan);
                    if (insertHealthplan > 0){
                        return insertHealthplan;
                    }
                    else {
                        throw new Exception("添加康复计划失败");
                    }
                }
                else {
                    throw new Exception("修改患者信息失败");
                }
            }
            else {
                throw new Exception("未查到该会员信息");
            }
        }
        else {
            throw new Exception("缺少必要参数");
        }
    }

    /**
     * 患者证件号获取运动处方
     * */
    @Override
    public List<LicenseNumExerciseVo> licenseNumExercise(String idCard) throws Exception {
        Patient patient = patientDao.licenseNumExercise(idCard);
        if (patient == null){
            patient = patient(idCard);
        }
        List<LicenseNumExerciseVo> licenseNumExerciseVoList = new ArrayList<>();

        List<PatientExerciseprescription> patientExerciseprescriptionList = patientExerciseprescriptionDao.patientCollect(patient.getPatientId());
        if (patientExerciseprescriptionList == null || patientExerciseprescriptionList.size() <= 0){
            patientExerciseprescriptionList = patientExerciseprescriptionDao.patientCollect(1);
        }

        if (patientExerciseprescriptionList != null && patientExerciseprescriptionList.size() > 0){
            for (PatientExerciseprescription patientExerciseprescription : patientExerciseprescriptionList) {
                Exerciseprescription exerciseprescription = exerciseprescriptionDao.queryById(patientExerciseprescription.getPrescriptionId());
                if (exerciseprescription != null){
                    LicenseNumExerciseVo licenseNumExerciseVo = new LicenseNumExerciseVo();
                    licenseNumExerciseVo.setExerciseId(exerciseprescription.getPrescriptionId());
                    licenseNumExerciseVo.setExerciseName(exerciseprescription.getPrescriptionName());
                    licenseNumExerciseVo.setExerciseUrl(exerciseprescription.getExercisePictureUrl());
                    licenseNumExerciseVo.setExerciseLevel(exerciseprescription.getExerciseLevel());
                    licenseNumExerciseVo.setExerciseCourse(exerciseprescription.getExerciseCourse());
                    licenseNumExerciseVo.setExerciseTime(exerciseprescription.getExerciseTime());
                    licenseNumExerciseVo.setHealthplanId(patientExerciseprescription.getFavouriteId());
                    licenseNumExerciseVoList.add(licenseNumExerciseVo);
                }
            }
        }

        return licenseNumExerciseVoList;
    }

    /**
     * 患者详细信息
     * */
    @Override
    public PatientDetailedVo patientDetailed(Integer id) {
        PatientDetailedVo patientDetailedVo = new PatientDetailedVo();
        Patient patient = patientDao.queryById(id);
        if (patient != null){
            patientDetailedVo.setId(patient.getPatientId());
            patientDetailedVo.setName(patient.getPatientName());
            patientDetailedVo.setSex(patient.getSex());
            patientDetailedVo.setAge(patient.getAge());
            patientDetailedVo.setCodeNumber(patient.getCodeNumber());
            patientDetailedVo.setAddress(patient.getAddress());
            patientDetailedVo.setAvatar(patient.getAvatar());

            List<PatientAppointment> patientAppointments = patientAppointmentDao.selectPatientAppointmentByPatientId(patient.getPatientId());
            if (patientAppointments != null && patientAppointments.size() > 0){
                patientDetailedVo.setCount(patientAppointments.size());
            }
            else {
                patientDetailedVo.setCount(0);
            }

            PatientAppointment patientAppointment = patientAppointmentDao.selectPatientAppointmentById(patient.getPatientId());
            if (patientAppointment != null){
                Doctor doctor = doctorDao.queryById(patientAppointment.getDoctorId());
                if (doctor != null){
                    patientDetailedVo.setDoctor(doctor.getDoctorName());
                }
                patientDetailedVo.setReserve(patientAppointment.getAppointmentTime() + " " + patientAppointment.getStartTime());
            }

            patientDetailedVo.setPhone(patient.getPhone());
            patientDetailedVo.setWeChat(patient.getWeChat());
//
//            /** 会员 */
//            private String customer;
//
//            /** 会员截止 */
//            private String time;
//
//            /** 付款方式 */
//            private String payType;

            if (patient.getBirthday() != null){
                patientDetailedVo.setBirthday(patient.getBirthday().toString());
            }
        }

        return patientDetailedVo;
    }

    /**
     * 查询待修改的患者信息
     * */
    @Override
    public Patient selPatient(Integer id) {
        Patient patient = patientDao.queryById(id);
        return patient;
    }

    /**
     * 修改患者信息
     * */
    @Override
    public int savePatient(Patient patient) {
        int update = patientDao.update(patient);
        return update;
    }

    /**
     * 患者抓小球需完成数量
     * */
    @Override
    public Integer needBallCount(String idCard) {
        Patient patient = patientDao.needBallCount(idCard);
        if (patient != null && patient.getBallCount() != null && patient.getBallCount() != 0){
            return patient.getBallCount();
        }

        return 0;
    }

    /**
     * 证件号获取患者信息(有则查询无则新增)
     * */
    @Override
    public Patient patient(String idCard) {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Patient patient = patientDao.needBallCount(idCard);
        if (patient != null){
            return patient;
        }
        else {
            Patient tmpPatient = new Patient();
            tmpPatient.setPatientName("患者" + format.format(new Date()));

            int ageByIdCard = getAgeByIdCard(idCard);
            tmpPatient.setAge(ageByIdCard);

            String genderByIdCard = getGenderByIdCard(idCard);
            tmpPatient.setSex(genderByIdCard);

            tmpPatient.setBirthday(idCard.substring(6, 10) + "-" + idCard.substring(10, 12) + "-" + idCard.substring(12, 14));
            tmpPatient.setRegisterTime(dateFormat.format(new Date()));
            tmpPatient.setIdCard(idCard);
            tmpPatient.setIdCardType(PublicConstants.IdCardType.ID_CARD.getValue());
            patientDao.insert(tmpPatient);
            return tmpPatient;
        }
    }

    /**
     * 患者管理
     * */
    @Override
    public IPage<Patient> management(HttpServletRequest request, ManagementVo managementVo) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        Doctor loginDoctor;
        try {
            loginDoctor = doctorService.getLoginDoctor(request);
        } catch (Exception e){
            throw new Exception("登录已过期");
        }

        Role role = roleDao.queryById(loginDoctor.getRoleId());
        if (role == null || !role.getRoleName().equals(PublicConstants.RoleEnum.SuperAdmin.getValue())){
            managementVo.setCode(loginDoctor.getHospitalCode());
        }

        Page<Patient> page = new Page<>(managementVo.getPageNo(), managementVo.getPageSize());
        IPage<Patient> patientPage = this.patientDao.management(page, managementVo);
        if (patientPage != null && patientPage.getSize() > 0){
            for (int i = 0; i < patientPage.getRecords().size(); i++) {
                Doctor doctor = doctorDao.selectDoctorById(patientPage.getRecords().get(i).getDoctorId());
                if (doctor != null){
                    patientPage.getRecords().get(i).setDoctorName(doctor.getDoctorName());
                }

//                if (patientPage.getRecords().get(i).getRegisterTime() != null){
//                    patientPage.getRecords().get(i).setRegisterDate(format.format(patientPage.getRecords().get(i).getRegisterTime()));
//                }
            }
        }
        return patientPage;
    }

    /**
     * 查询待修改的患者信息
     * */
    @Override
    public Patient patientDetails(Integer id) {
        Patient patient = patientDao.patientDetails(id);
        return patient;
    }

    /**
     * 修改患者信息
     * */
    @Override
    public int editPatient(Patient patient) {
        int i = patientDao.update(patient);
        return i;
    }

    /**
     * 患者上传头像
     * */
    @Override
    public String puploadFile(MultipartFile file) throws Exception {
        String uploadFile;
        try {
            uploadFile = minioUtil.uploadFile(file, "patient", "avatar");
        } catch (Exception e){
            throw new Exception("文件上传失败");
        }

        return uploadFile;
    }

    /**
     * 查询患者返回值赋值
     * */
    public List<PatientVo> patientVo(List<Patient> patientList) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        if (patientList != null && patientList.size() > 0){
            List<PatientVo> patientVoList = new ArrayList<>();
            for (Patient patient : patientList) {
                if (patient.getPatientAppointmentList() != null && patient.getPatientAppointmentList().size() > 0){
                    for (PatientAppointment patientAppointment : patient.getPatientAppointmentList()) {
                        PatientVo patientVo = new PatientVo();
                        patientVo.setPatientId(patient.getPatientId());
                        patientVo.setPatientName(patient.getPatientName());
                        patientVo.setAge(patient.getAge());
                        patientVo.setSex(patient.getSex());
                        //患者手机号不能为空，且必须为11位
                        if (patient.getPhone() != null && !patient.getPhone().equals("") && patient.getPhone().length() == 11){
                            //手机号返回格式：186****0123
                            patientVo.setPhone(patient.getPhone().substring(0, 3) + "****" + patient.getPhone().substring(patient.getPhone().length() - 4));
                        }

                        //患者注册时间不能为空
                        if (patient.getRegisterTime() != null && !patient.getRegisterTime().equals("")){
                            patientVo.setRegisterTime(patient.getRegisterTime());
                        }

                        patientVo.setDoctorName(patientAppointment.getDoctorName());

                        //检查状态枚举不能为空
                        if (patientAppointment.getCheckStatus() != null && !patientAppointment.getCheckStatus().equals("")){
                            if (patientAppointment.getCheckStatus().equals(PublicConstants.Checkstatus.NotChecked.getValue())){
                                patientVo.setCheckStatus("未检查");
                            }
                            else if (patientAppointment.getCheckStatus().equals(PublicConstants.Checkstatus.UnderTreatment.getValue())){
                                patientVo.setCheckStatus("治疗中");
                            }
                            else if (patientAppointment.getCheckStatus().equals(PublicConstants.Checkstatus.EndOfTreatment.getValue())){
                                patientVo.setCheckStatus("治疗结束");
                            }
                            else {
                                throw new Exception("检查状态枚举出错了");
                            }
                        }

                        //预约时间不能为空
                        if (patientAppointment.getAppointmentTime() != null && !patientAppointment.getAppointmentTime().equals("")){
                            patientVo.setAppointmentTime(patientAppointment.getAppointmentTime());
                        }

                        //预约单价格不能为空
                        if (patientAppointment.getPrice() != null && !patientAppointment.getPrice().equals("")){
                            BigDecimal price;
                            try {
                                price = new BigDecimal(patientAppointment.getPrice().toString());
                            } catch (Exception e){
                                throw new Exception("预约单价格转换错误");
                            }
                            patientVo.setPrice(price);
                        }

                        patientVoList.add(patientVo);
                    }
                }
            }
            return patientVoList;
        }
        else {
            throw new Exception("患者信息不能为空");
        }
    }

    /**
     * 根据身份号获取年龄
     */
    public static int getAgeByIdCard(String idNo) {
        try {
            Calendar currentDate = Calendar.getInstance();

            int bornYear = Integer.valueOf(idNo.substring(6, 10));
            int bornMonth = Integer.valueOf(idNo.substring(10, 12));
            int bornDay = Integer.valueOf(idNo.substring(12, 14));

            int currentYear = currentDate.get(Calendar.YEAR);
            int currentMonth = currentDate.get(Calendar.MONTH) + 1;
            int currentDay = currentDate.get(Calendar.DATE);

            int age = currentYear - bornYear;
            if (bornMonth  > currentMonth ||
                    (bornMonth == currentMonth && bornDay > currentDay)) {
                age--;
            }
            return age;
        } catch (Throwable e) {
            String errMsg = String.format("年龄计算失败, idNo:%s", idNo);
            throw new RuntimeException(errMsg, e);
        }
    }

    /**
     * 根据身份编号获取性别
     */
    public static String getGenderByIdCard(String idCard) {
        String sGender;

        String sCardNum = idCard.substring(16, 17);
        if (Integer.parseInt(sCardNum) % 2 != 0) {
            sGender = "male";
        } else {
            sGender = "female";
        }
        return sGender;
    }
}